r"""
 models.py

 Tutt Library Systems Task Planner Models

 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

     http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.

 Copyright Jeremy Nelson, Colorado College
 """
__author__ = "Jeremy Nelson"
__version__ = "0.1.1"

import datetime,os,logging,urllib2
from google.appengine.ext import db
from google.appengine.api import users


def __get_collection__(instance,property_name):
    output = []
    if hasattr(instance,property_name):
        all_keys = getattr(instance,property_name)
        for row in all_keys:
            output.append(db.get(row))
    return output
        

class Log(db.Model):
    """
    The `Log` models a specific event that can be associated
    with either a `Task` or `Project`.
    """
    created_by = db.UserProperty()
    created_on = db.DateTimeProperty(auto_now_add=True)
    days = db.ListProperty(datetime.datetime,
                           default=None)
    description = db.StringProperty()
    entities = db.ListProperty(db.Key,
                               default=None)
    tags = db.ListProperty(db.Category,
                           default=None)

    def get_entities(self):
        return __get__collection__(self,'entities')




class Person(db.Model):
    """
    The `Person` models library staff for task assignment
    and project roles
    """
    cc_email = db.EmailProperty()
    family = db.StringProperty(required=True)
    given = db.StringProperty()
    login = db.UserProperty()

class Project(db.Model):
    """
    The `Project` class organizes a set of tasks
    """
    # dependencies can include specific tasks or other
    # projects
    created_on = db.DateTimeProperty(auto_now_add=True)
    dependencies = db.ListProperty(db.Key,
                                   default=None)
    end_date = db.DateTimeProperty()
    name = db.StringProperty(required=True)
    tasks = db.ListProperty(db.Key,
                            default=None)
    start_date = db.DateTimeProperty(required=True)

    def get_dependencies(self):
        return __get_collection__(self,'dependencies')

    def get_logs(self):
        output = []
        all_logs = db.GqlQuery('SELECT * FROM Log WHERE entities=:1',self.key())
        for row in all_logs:
            output.append(row)
        return output

    def get_status(self):
        completed_tasks = 0
        tasks = self.get_tasks()
        for task in tasks:
            if task.completed_on_date is not None:
                completed_tasks += 1
        if datetime.datetime.today() >= self.end_date and\
           completed_tasks < len(tasks):
            return {'msg':'Late',
                    'detail':'%s out of %s tasks outstanding, project due on %s' %\
                    (len(tasks) - completed_tasks,
                     len(tasks),
                     self.end_date.strftime('%m-%d-%Y'))}
        if completed_tasks == len(tasks):
            if self.end_date is None:
                self.end_date = datetime.datetime.today()
                self.put()
            return {'msg':'Completed',
                    'detail':'All %s tasks completed on %s' %\
                    (len(tasks),
                     self.end_date.strftime('%m-%d-%Y'))}
        else:
            return {'msg':'In Progress',
                    'detail':'%s tasks completed out of %s' %\
                    (completed_tasks,len(tasks))}
           

    def get_tasks(self):
        return __get_collection__(self,'tasks')

    def total_days(self):
        size = 0
        tasks = self.get_tasks()
        for task in tasks:
            size += task.total_days()
        return size
    

class Role(db.Model):
    """
    The `Role` associates people with a particular role in a
    project.
    """
    description = db.StringProperty()
    people = db.ListProperty(db.Key,
                             default=None)

class System(db.Model):
    """
    The `System` lists web-based systems that are
    checked frequently for 200 status code
    """
    name = db.StringProperty(required=True)
    src_repository_url = db.LinkProperty()
    url = db.LinkProperty()
    
class Task(db.Model):
    """
    Basic task class for tuttsystems application
    """
    assigned_to = db.ListProperty(db.Key,
                                  default=None)
    completed_on_date = db.DateTimeProperty()
    created_on = db.DateTimeProperty(auto_now_add=True)
    created_by = db.UserProperty()
    dependencies = db.ListProperty(db.Key,
                                   default=None)
    description = db.StringProperty(required=True)
    estimate_finished_date = db.DateTimeProperty()
    is_milestone = db.BooleanProperty(default=False)
    start_date = db.DateTimeProperty()
    tags = db.ListProperty(db.Category,
                           default=None)

    def get_dependencies(self):
        return __get_collection__(self,'dependencies')
    
    def get_assignees(self):
        return __get_collection__(self,'assigned_to')

    def get_logs(self):
        output = []
        all_logs = db.GqlQuery('SELECT * FROM Log WHERE entities=:1',self.key())
        for row in all_logs:
            output.append(row)
        return output


    def total_days(self):
        """
        Helper function calculates the time span based on values
        in instance
        """
        logs = self.get_logs()
        if len(logs) > 0:
            first_date = logs[0].days[0]
        else:
            first_date = self.created_on
        if self.completed_on_date is not None:
            last_date = self.completed_on
        elif self.estimate_finished_date is not None:
            last_date = self.estimate_finished_date
        elif len(logs) > 1:
            last_date = logs[-1].days[-1]
        else:
            last_date = datetime.datetime.today()
        time_delta = last_date - first_date           
        return time_delta.days

        
        

